use std::collections::VecDeque;

use serde::Deserialize;

use crate::{testcase::TestCase, utils::{sheet_to_test_cases, stack_to_test_case}};

#[derive(Deserialize, Debug)]
#[serde(transparent)]
pub struct Xmind {
    pub sheets: Vec<Sheet>,
}

#[derive(Deserialize, Debug)]
pub struct Sheet {
    pub id: String,
    pub title: String,
    #[serde(rename = "rootTopic")]
    pub root_topic: Node,
}

#[derive(Deserialize, Debug)]
pub struct Node {
    pub id: String,
    pub title: String,
    pub children: Option<Children>,
    /// 节点链接
    pub href: Option<String>,
    /// 节点label
    pub labels: Option<Vec<String>>,
    /// 节点notes
    pub notes: Option<Notes>,
    /// 节点markers
    pub markers: Option<Vec<Marker>>,
}

#[derive(Deserialize, Debug)]
pub struct Children {
    pub attached: Vec<Node>,
}

#[derive(Deserialize, Debug)]
pub struct Notes {
    pub plain: NotesPlain,
}

#[derive(Deserialize, Debug)]
pub struct NotesPlain {
    pub content: String,
}

#[derive(Deserialize, Debug)]
pub struct Marker {
    #[serde(rename = "markerId")]
    pub marker_id: String,
}

impl Xmind {
    fn get_test_case_sheet(mut self) -> Sheet {
        let mut test_case_sheet = self.get_sheet_by_name("测试用例");
        let mut candidate_nodes = test_case_sheet.root_topic.get_mut_children();

        while let Some(node) = candidate_nodes.pop() {
            match node.href {
                // 当href为空, 继续迭代子节点
                None => candidate_nodes.extend(node.get_mut_children()),
                // 当href不为空, 关联链接节点
                Some(ref href) => {
                    let id = &href[7..];
                    let sheet = self.get_sheet_by_id(id);
                    node.children = sheet.root_topic.children;
                    // 链接节点的子节点, 不再继续关联
                }
            }
        }

        test_case_sheet
    }

    fn get_sheet_by_name(&mut self, name: &str) -> Sheet {
        for index in 0..self.sheets.len() {
            let sheet = &self.sheets[index];
            if sheet.title == name {
                return self.sheets.remove(index);
            }
        }
        panic!("Cannot found sheet: {}", name)
    }

    fn get_sheet_by_id(&mut self, id: &str) -> Sheet {
        for index in 0..self.sheets.len() {
            let sheet = &self.sheets[index];
            if sheet.root_topic.id == id {
                return self.sheets.remove(index);
            }
        }
        panic!("Cannot found sheet by id: {}", id)
    }

    pub fn convert_to_test_cases(mut self) -> Vec<TestCase> {
        let sheet = self.get_test_case_sheet();
        sheet_to_test_cases(sheet)
    }
}

impl Node {
    pub fn get_children(&self) -> Vec<&Node> {
        self.children
            .as_ref()
            .map(|c| c.attached.iter().rev().collect())
            .unwrap_or_default()
    }

    pub fn get_mut_children(&mut self) -> Vec<&mut Node> {
        self.children
            .as_mut()
            .map(|c| c.attached.iter_mut().collect())
            .unwrap_or_default()
    }

    pub fn has_children(&self) -> bool {
        self.get_children().len() > 0
    }
}

#[cfg(test)]
mod tests {
    use crate::utils::load_xmind;

    use super::*;
    #[test]
    fn get_test_case_sheet() {
        let path = std::path::Path::new("/mnt/d/Desktop/AI-DBSv1.0测试用例.xmind");
        let xmind = load_xmind(path).unwrap();
        let sheet = xmind.get_test_case_sheet();
        println!("{:?}", sheet);
    }
}
